package org.springboot.redis.controller;

import org.springboot.redis.dao.RedisCacheDao;
import org.springboot.redis.dao.RedisDao;
import org.springboot.redis.entity.Book;
import org.springboot.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/redis")
public class RedisController {
	
	@Autowired
	RedisDao redisDao;
	
	@Autowired
	RedisCacheDao redisCacheDao;
	
	@Autowired
	RedisService redisService;
	
	/**
	 * 缓存穿透
	 * 场景: Redis 和数据库中都没有找到想要的数据时会发生
	 * 解决方案: 
	 *  1. 缓存空结果: 过期时间不能太长
	 *  2. 用户合法性校验: 拦截恶意请求
	 *  3. 布隆过滤器: 存在一定误判的可能性，但可以拦截掉大部分一定不存在的数据
	 * 
	 * 缓存击穿
	 * 场景: Redis 数据过期时接收到大量请求
	 * 解决方案: 
	 *  1. 热点数据永不过期: 过期前刷新
	 *  2. 使用互斥锁: 影响吞吐量
	 * 
	 * 缓存雪崩
	 * 场景: Redis 的大量热点 key 在某个时间同时失效
	 * 解决方案: 
	 * 	1. 失效时间加上随机数: 增加维护成本
	 *  2. 热点数据永不过期: 过期前刷新
	 *  3. 缓存预热: 启动前先用脚本将缓存数据写入缓存系统
	 *  
	 * 缓存更新
	 * 常见更新策略: 
	 * 1. 先删缓存，再更新数据库: 易读到脏数据，一般不用
	 * 2. 先更新数据库，再删缓存(常用): 并发写比读快时会读到脏数据(错误几率小)
	 * 3. 先更新数据库，再更新缓存: 并发先后写入时会读到脏数据
	 * 4. read/write through: 数据库由缓存代理
	 * 5. Write Behind: 写回，更新数据时，只更新缓存，不更新数据库，缓存会异步地批量更新数据库
	 */

	@RequestMapping(value = "/setKey", method = RequestMethod.GET)
    public String setKey(String key, String value) {
        redisDao.setKey(key, value);
        return "success";
    }
	
	@RequestMapping(value = "/getValue", method = RequestMethod.GET)
    public String getValue(String key) {
        return redisDao.getValue(key);
    }
	
	@RequestMapping(value = "/tmpl/sendMsg", method = RequestMethod.GET)
	public String tmplSendMsg(String msg) {
		redisService.tmplSendMsg(msg);
		return "success";
	}
	
	@RequestMapping(value = "/jedis/sendMsg", method = RequestMethod.GET)
	public String jedisSendMsg(String msg) {
		redisService.jedisSendMsg(msg);
		return "success";
	}
	
	@RequestMapping(value = "/jedis/subscribe", method = RequestMethod.GET)
	public String subscribe() {
		redisService.subscribe();
		return "success";
	}
	
	@RequestMapping(value = "/jedis/unsubscribe", method = RequestMethod.GET)
	public String unsubscribe() {
		redisService.unsubscribe();
		return "success";
	}
	
	@RequestMapping(value = "/tmpl/getByIsbn", method = RequestMethod.GET)
	public Book tmplGetByIsbn(String key) {
		return redisCacheDao.getByIsbn(key);
	}
	
	@RequestMapping(value = "/tmpl/putByIsbn", method = RequestMethod.GET)
	public Book tmplPutByIsbn(String key) {
		return redisCacheDao.putByIsbn(key);
	}
	
	@RequestMapping(value = "/tmpl/evictByIsbn", method = RequestMethod.GET)
	public String tmplEvictByIsbn(String key) {
		return redisCacheDao.evictByIsbn(key);
	}
	
	@RequestMapping(value = "/tmpl/evictAll", method = RequestMethod.GET)
	public String tmplEvictAll(String key) {
		return redisCacheDao.evictAll(key);
	}
}
